Multithreading এবং Concurrency (মাল্টিথ্রেডিং এবং কনকারেন্সি)

Computer Programming - সি স্ট্যান্ডার্ড লাইব্রেরি রেফারেন্স (C Standard Library Reference)
229
229

Multithreading এবং Concurrency (মাল্টিথ্রেডিং এবং কনকারেন্সি)

মাল্টিথ্রেডিং এবং কনকারেন্সি সি প্রোগ্রামিং ভাষায় একাধিক কাজ একযোগে সম্পাদনের জন্য ব্যবহৃত হয়। মাল্টিথ্রেডিং একটি প্রক্রিয়ায় একাধিক থ্রেড তৈরি করে বিভিন্ন কাজ একই সময়ে সম্পন্ন করে, যেখানে কনকারেন্সি হলো একাধিক কাজের মধ্যে সঠিকভাবে ক্রম তৈরি করার কৌশল।

মাল্টিথ্রেডিং কী?

মাল্টিথ্রেডিং হলো একই প্রক্রিয়ার অধীনে একাধিক থ্রেড তৈরি করে একাধিক কাজ করার প্রক্রিয়া। প্রতিটি থ্রেড একই অ্যাড্রেস স্পেস ভাগ করে এবং প্রোগ্রামের আলাদা অংশ সম্পন্ন করে। এটি প্রোগ্রামের গতি বৃদ্ধি করে এবং প্রসেসরের ক্ষমতা সর্বোচ্চ পর্যায়ে পৌঁছে দেয়।


মাল্টিথ্রেডিং সি প্রোগ্রামে কিভাবে কাজ করে?

সি প্রোগ্রামে মাল্টিথ্রেডিং বাস্তবায়নের জন্য POSIX Threads (Pthreads) ব্যবহার করা হয়। এটি একটি পোর্টেবল থ্রেডিং লাইব্রেরি, যা থ্রেড তৈরি, পরিচালনা, এবং সমন্বয় করতে ব্যবহৃত হয়। pthread.h হেডার ফাইলের মাধ্যমে Pthreads ফাংশনগুলো ব্যবহৃত হয়।

গুরুত্বপূর্ণ Pthreads ফাংশন

ফাংশনকাজ
pthread_create()নতুন থ্রেড তৈরি করে
pthread_join()একটি থ্রেড শেষ হওয়া পর্যন্ত অপেক্ষা করে
pthread_exit()থ্রেড থেকে বেরিয়ে যায়
pthread_cancel()একটি থ্রেড বন্ধ করে
pthread_mutex_lock()মিউটেক্স লক সেট করে
pthread_mutex_unlock()মিউটেক্স আনলক করে

১. pthread_create() – থ্রেড তৈরি করা

pthread_create() ফাংশনটি একটি নতুন থ্রেড তৈরি করতে ব্যবহৃত হয়। এটি থ্রেডের জন্য একটি ফাংশন এবং আর্গুমেন্ট গ্রহণ করে এবং থ্রেডটি তৈরি হলে সেই ফাংশনটি কার্যকর হয়।

সিঙ্কট্যাক্স:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

উদাহরণ:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *print_message(void *arg) {
    printf("Hello from thread!\n");
    return NULL;
}

int main() {
    pthread_t thread;
    
    // নতুন থ্রেড তৈরি করা
    pthread_create(&thread, NULL, print_message, NULL);
    
    // থ্রেড শেষ হওয়ার জন্য অপেক্ষা করা
    pthread_join(thread, NULL);
    
    printf("Hello from main!\n");
    return 0;
}

Output:

Hello from thread!
Hello from main!

Note: pthread_join() মূল থ্রেডকে নতুন থ্রেড শেষ হওয়া পর্যন্ত অপেক্ষা করতে বাধ্য করে।


২. pthread_join() – থ্রেডের সমাপ্তির জন্য অপেক্ষা

pthread_join() ফাংশনটি মূল থ্রেডকে নির্দিষ্ট থ্রেডের সমাপ্তি পর্যন্ত অপেক্ষা করতে বাধ্য করে।

সিঙ্কট্যাক্স:

int pthread_join(pthread_t thread, void **retval);

৩. pthread_mutex_lock() এবং pthread_mutex_unlock() – মিউটেক্স লক

মাল্টিথ্রেডিং প্রোগ্রামে একাধিক থ্রেড একই ডেটায় একযোগে কাজ করলে রেস কন্ডিশন তৈরি হতে পারে। এটি এড়াতে মিউটেক্স (Mutex) ব্যবহার করা হয়, যা থ্রেডকে একে অপরের সাথে সমন্বয় করতে সহায়ক।

  • pthread_mutex_lock() ফাংশনটি মিউটেক্স লক করে, অর্থাৎ নির্দিষ্ট থ্রেডকে একটি ক্রিটিকাল সেকশনে এককভাবে কাজ করার অনুমতি দেয়।
  • pthread_mutex_unlock() ফাংশনটি মিউটেক্স আনলক করে, যাতে অন্য থ্রেড ক্রিটিকাল সেকশনে প্রবেশ করতে পারে।

উদাহরণ:

#include <stdio.h>
#include <pthread.h>

int counter = 0;
pthread_mutex_t lock;

void *increment_counter(void *arg) {
    pthread_mutex_lock(&lock);    // লক করা
    counter++;
    printf("Counter: %d\n", counter);
    pthread_mutex_unlock(&lock);  // আনলক করা
    return NULL;
}

int main() {
    pthread_t thread1, thread2;
    pthread_mutex_init(&lock, NULL);  // মিউটেক্স ইনিশিয়ালাইজ করা

    pthread_create(&thread1, NULL, increment_counter, NULL);
    pthread_create(&thread2, NULL, increment_counter, NULL);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    pthread_mutex_destroy(&lock);  // মিউটেক্স ধ্বংস করা
    return 0;
}

Output: (Output may vary due to thread scheduling)

Counter: 1
Counter: 2

কনকারেন্সি (Concurrency)

কনকারেন্সি হলো একাধিক কাজ বা প্রসেসকে এমনভাবে সমন্বয় করা, যাতে তারা একে অপরের সাথে সংঘর্ষে না আসে। মাল্টিথ্রেডিং এবং কনকারেন্সি একে অপরের সাথে সম্পর্কিত, তবে কনকারেন্সি শুধু মাল্টিথ্রেডিংয়ে নয় বরং সিঙ্গল-থ্রেড অ্যাপ্লিকেশনেও দেখা যেতে পারে।

কনকারেন্সির উদাহরণ

কনকারেন্সি সাধারণত তখনই ব্যবহৃত হয় যখন একাধিক থ্রেড বা প্রসেস একই রিসোর্সে কাজ করে। উদাহরণস্বরূপ, ব্যাংকিং সফটওয়্যারে একই অ্যাকাউন্ট থেকে একাধিক লেনদেন কনকারেন্টলি (একযোগে) করতে গেলে রেস কন্ডিশন তৈরি হতে পারে। এ ধরনের সমস্যা এড়াতে লক এবং সিঙ্ক্রোনাইজেশন কৌশল ব্যবহার করতে হয়।


মাল্টিথ্রেডিং এবং কনকারেন্সির সুবিধা

১. দ্রুত ডেটা প্রক্রিয়াকরণ: একাধিক থ্রেড ব্যবহার করে প্রোগ্রামের কার্যক্ষমতা বৃদ্ধি পায়।
২. সমান্তরাল ডেটা প্রসেসিং: বিভিন্ন ডেটা সমান্তরালে প্রসেস করা সম্ভব হয়।
৩. রেস কন্ডিশন হ্রাস: মিউটেক্স ও লক ব্যবহার করে থ্রেডের মধ্যে সংঘর্ষ কমানো সম্ভব।
৪. ব্যবহারকারীর অভিজ্ঞতা উন্নত: একই সময়ে একাধিক কাজের জন্য অপেক্ষা কমে যায় এবং ব্যবহারকারীর অভিজ্ঞতা উন্নত হয়।


সারসংক্ষেপ

ফাংশনকাজ
pthread_create()নতুন থ্রেড তৈরি করে
pthread_join()নির্দিষ্ট থ্রেড শেষ হওয়া পর্যন্ত অপেক্ষা করে
pthread_mutex_lock()মিউটেক্স লক করে এবং থ্রেডকে একক অ্যাক্সেস দেয়
pthread_mutex_unlock()মিউটেক্স আনলক করে, যাতে অন্য থ্রেড অ্যাক্সেস পায়

মাল্টিথ্রেডিং এবং কনকারেন্সি সি প্রোগ্রামিংয়ে প্রোগ্রামিং দক্ষতা বৃদ্ধি করে এবং প্রসেসরের কার্যক্ষমতা সর্বাধিক করে। Pthreads লাইব্রেরি ব্যবহার করে মাল্টিথ্রেডিং বাস্তবায়ন করা সহজ হয় এবং মিউটেক্স ও লক ব্যবহার করে কনকারেন্সি সমস্যা সমাধান করা যায়।

common.content_added_by

pthread.h এবং POSIX Thread Library এর প্রয়োগ

214
214

pthread.h এবং POSIX Thread Library এর প্রয়োগ

pthread.h হেডার ফাইলটি সি প্রোগ্রামিং ভাষায় POSIX থ্রেড লাইব্রেরি (Portable Operating System Interface Threads Library) ব্যবহারের জন্য ব্যবহৃত হয়। POSIX থ্রেড লাইব্রেরি সি প্রোগ্রামিংয়ে মাল্টিথ্রেডিং কার্যকারিতা যোগ করার একটি স্ট্যান্ডার্ড উপায়। মাল্টিথ্রেডিং এমন একটি কৌশল, যার মাধ্যমে প্রোগ্রাম একাধিক অংশে বিভক্ত হয়ে সমান্তরালভাবে কাজ করতে পারে, যা সিপিইউর কার্যক্ষমতা এবং প্রোগ্রামের কর্মদক্ষতা বৃদ্ধি করে।


POSIX থ্রেড লাইব্রেরি (Pthreads) এর প্রয়োজনীয়তা

১. সমান্তরাল প্রক্রিয়াকরণ: একাধিক কাজ সমান্তরালে চালাতে থ্রেড ব্যবহার করা হয়, যা প্রোগ্রামের পারফরম্যান্স বৃদ্ধি করে।
২. CPU রিসোর্সের সর্বোচ্চ ব্যবহার: মাল্টিপ্রসেসর সিস্টেমে বিভিন্ন থ্রেড আলাদা আলাদা কোরে চলতে পারে, যা CPU-এর রিসোর্সের সর্বোচ্চ ব্যবহার নিশ্চিত করে।
৩. প্রোগ্রামের প্রতিক্রিয়াশীলতা বৃদ্ধি: মাল্টিথ্রেডিংয়ের মাধ্যমে প্রোগ্রাম আরও দ্রুত এবং প্রতিক্রিয়াশীল হয়, কারণ থ্রেডগুলো সমান্তরালে কাজ করতে পারে।
৪. ডেটা শেয়ারিং: একাধিক থ্রেড সহজেই একে অপরের ডেটা শেয়ার এবং অ্যাক্সেস করতে পারে, যা মাল্টিপ্রসেসিংয়ের তুলনায় আরও কার্যকর।


pthread.h এর গুরুত্বপূর্ণ ফাংশনসমূহ

pthread.h হেডার ফাইলে কিছু গুরুত্বপূর্ণ ফাংশন রয়েছে যা থ্রেড তৈরি, থ্রেড পরিচালনা, এবং থ্রেড সিঙ্ক্রোনাইজেশন করতে ব্যবহৃত হয়। নিচে তাদের ব্যাখ্যা দেওয়া হলো।

১. pthread_create() – থ্রেড তৈরি করা

pthread_create() ফাংশনটি একটি নতুন থ্রেড তৈরি করতে ব্যবহৃত হয় এবং এটি সফলভাবে তৈরি হলে থ্রেডের ID রিটার্ন করে।

সিঙ্কট্যাক্স:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
  • thread: থ্রেড আইডি সঞ্চয় করতে পয়েন্টার।
  • attr: থ্রেডের বৈশিষ্ট্য নির্ধারণ করতে ব্যবহৃত (NULL হলে ডিফল্ট বৈশিষ্ট্য)।
  • start_routine: থ্রেডের মেইন ফাংশন বা কাজের ফাংশনের পয়েন্টার।
  • arg: থ্রেডের মেইন ফাংশনে পাস করা আর্গুমেন্ট।

উদাহরণ:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *print_message(void *message) {
    printf("%s\n", (char *)message);
    return NULL;
}

int main() {
    pthread_t thread;
    const char *message = "Hello, Thread!";

    // থ্রেড তৈরি
    if (pthread_create(&thread, NULL, print_message, (void *)message)) {
        fprintf(stderr, "Error creating thread\n");
        return 1;
    }

    // থ্রেডের সমাপ্তির জন্য অপেক্ষা
    pthread_join(thread, NULL);
    return 0;
}

২. pthread_join() – থ্রেড সমাপ্তির জন্য অপেক্ষা করা

pthread_join() ফাংশনটি একটি নির্দিষ্ট থ্রেড শেষ হওয়া পর্যন্ত অপেক্ষা করতে ব্যবহৃত হয়। এটি থ্রেড সিঙ্ক্রোনাইজেশনের জন্য গুরুত্বপূর্ণ।

সিঙ্কট্যাক্স:

int pthread_join(pthread_t thread, void **retval);
  • thread: যে থ্রেডটির জন্য অপেক্ষা করতে হবে তার ID।
  • retval: থ্রেডের রিটার্ন মান সঞ্চয় করার জন্য পয়েন্টার।

৩. pthread_exit() – থ্রেড শেষ করা

pthread_exit() ফাংশনটি একটি থ্রেডের কার্যকলাপ শেষ করতে ব্যবহৃত হয়। এটি অন্য থ্রেডের কার্যক্রমে কোনো ব্যাঘাত না ঘটিয়ে বর্তমান থ্রেড শেষ করে।

সিঙ্কট্যাক্স:

void pthread_exit(void *retval);
  • retval: থ্রেডের রিটার্ন মান।

উদাহরণ:

void *my_thread(void *arg) {
    printf("Thread is running\n");
    pthread_exit(NULL);  // থ্রেড শেষ করা
}

৪. pthread_mutex_t – মিউটেক্স লক

মাল্টিথ্রেডিংয়ের সময় ডেটা রেস বা একাধিক থ্রেড একই ডেটা অ্যাক্সেস করলে সমস্যা দেখা দিতে পারে। এই সমস্যা সমাধানে মিউটেক্স লক (Mutex Lock) ব্যবহার করা হয়, যা একটি নির্দিষ্ট সময়ে একাধিক থ্রেডের একই ডেটা অ্যাক্সেস করা বন্ধ করে।

মিউটেক্স ব্যবহারের ফাংশনসমূহ:

  • pthread_mutex_init() – মিউটেক্স লক আরম্ভ করা।
  • pthread_mutex_lock() – মিউটেক্স লক করা।
  • pthread_mutex_unlock() – মিউটেক্স আনলক করা।
  • pthread_mutex_destroy() – মিউটেক্স লক ধ্বংস করা।

উদাহরণ:

#include <stdio.h>
#include <pthread.h>

pthread_mutex_t lock;  // মিউটেক্স লক ডিক্লেয়ার

void *increment_counter(void *arg) {
    pthread_mutex_lock(&lock);  // লক করা
    int *counter = (int *)arg;
    (*counter)++;
    printf("Counter: %d\n", *counter);
    pthread_mutex_unlock(&lock);  // আনলক করা
    return NULL;
}

int main() {
    pthread_t thread1, thread2;
    int counter = 0;

    pthread_mutex_init(&lock, NULL);  // মিউটেক্স আরম্ভ করা

    pthread_create(&thread1, NULL, increment_counter, &counter);
    pthread_create(&thread2, NULL, increment_counter, &counter);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    pthread_mutex_destroy(&lock);  // মিউটেক্স ধ্বংস করা

    return 0;
}

POSIX থ্রেড লাইব্রেরির অন্যান্য ফাংশন

ফাংশনকাজ
pthread_self()বর্তমান থ্রেডের ID রিটার্ন করে।
pthread_equal()দুটি থ্রেডের ID সমান কিনা তা যাচাই করে।
pthread_cancel()একটি থ্রেড বাতিল করতে ব্যবহৃত হয়।
pthread_detach()থ্রেডকে পৃথক বা detached করার জন্য ব্যবহৃত হয়।
pthread_attr_init()থ্রেড অ্যাট্রিবিউট আরম্ভ করার জন্য ব্যবহৃত হয়।

সারসংক্ষেপ

POSIX থ্রেড লাইব্রেরি মাল্টিথ্রেডেড প্রোগ্রামিংয়ের জন্য সি প্রোগ্রামিংয়ে একটি মানসম্মত উপায় সরবরাহ করে। pthread.h হেডার ফাইলটি ব্যবহার করে মাল্টিথ্রেডেড প্রোগ্রাম তৈরি করা যায়, যা কর্মদক্ষতা বৃদ্ধি এবং CPU রিসোর্সের সর্বোত্তম ব্যবহার নিশ্চিত করে।

Pthreads লাইব্রেরির মাধ্যমে থ্রেড তৈরি, থ্রেডের মধ্যে সমন্বয় এবং সিঙ্ক্রোনাইজেশন সহজেই করা সম্ভব, যা জটিল প্রোগ্রামিং পরিবেশে কর্মক্ষমতা উন্নত করতে সহায়ক।

common.content_added_by

Thread Creation, Synchronization এবং Mutex Handling

249
249

Thread Creation, Synchronization এবং Mutex Handling

সি প্রোগ্রামিং ভাষায় থ্রেড ব্যবহার এবং মিউটেক্স (mutex) হ্যান্ডলিং সাধারণত POSIX Threads (pthreads) লাইব্রেরি ব্যবহার করে করা হয়। থ্রেড তৈরি, সিঙ্ক্রোনাইজেশন এবং মিউটেক্স ব্যবহৃত হয় বহুসংখ্যক থ্রেডের মধ্যে সঠিকভাবে কাজ করতে এবং মেমোরি রেস কন্ডিশন (race condition) এড়াতে। নিচে থ্রেড তৈরি, সিঙ্ক্রোনাইজেশন এবং মিউটেক্স হ্যান্ডলিংয়ের বিস্তারিত আলোচনা করা হলো।


1. Thread Creation

থ্রেড হলো একটি প্রক্রিয়ার মধ্যে কাজ করার স্বতন্ত্র একক। থ্রেড তৈরি করতে pthread_create() ফাংশনটি ব্যবহার করা হয়।

সিঙ্কট্যাক্স:

#include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine)(void *), void *arg);
  • thread: নতুন থ্রেডের জন্য একটি পয়েন্টার।
  • attr: থ্রেডের অ্যাট্রিবিউট সেটিংস (সাধারণত NULL পাঠানো হয়)।
  • start_routine: থ্রেডের জন্য শুরু হওয়া ফাংশন।
  • arg: শুরু হওয়া ফাংশনে পাস করা আর্গুমেন্ট (যদি প্রয়োজন হয়)।

উদাহরণ:

#include <stdio.h>
#include <pthread.h>

void *hello_world(void *arg) {
    printf("Hello from thread!\n");
    return NULL;
}

int main() {
    pthread_t thread;  // থ্রেড ডিক্লেয়ারেশন

    // থ্রেড তৈরি
    if (pthread_create(&thread, NULL, hello_world, NULL) != 0) {
        perror("Thread creation failed");
        return 1;
    }

    // থ্রেডের শেষ হওয়া পর্যন্ত অপেক্ষা করা
    pthread_join(thread, NULL);

    printf("Thread finished executing.\n");
    return 0;
}

এখানে pthread_create() ফাংশনটি একটি নতুন থ্রেড তৈরি করেছে, যা hello_world() ফাংশনটি চালাবে। pthread_join() ফাংশনটি থ্রেডটি শেষ হওয়া পর্যন্ত অপেক্ষা করে।


2. Thread Synchronization

থ্রেড সিঙ্ক্রোনাইজেশন নিশ্চিত করে যে একাধিক থ্রেডের মধ্যে কোনও ডেটা কনফ্লিক্ট বা রেস কন্ডিশন (যখন একাধিক থ্রেড একই ডেটা এক্সেস করে) না ঘটে। সিঙ্ক্রোনাইজেশন বিভিন্ন মেকানিজমের মাধ্যমে করা হয়, যেমন মিউটেক্স (mutexes), কন্ডিশন ভেরিয়েবল, সেমাফোর ইত্যাদি।

সিঙ্ক্রোনাইজেশন এর উদাহরণ:

#include <stdio.h>
#include <pthread.h>

pthread_mutex_t mutex;  // মিউটেক্স ডিক্লেয়ারেশন

void *increment(void *arg) {
    pthread_mutex_lock(&mutex);  // মিউটেক্স লক করা

    // critical section
    printf("Thread is executing\n");

    pthread_mutex_unlock(&mutex);  // মিউটেক্স আনলক করা
    return NULL;
}

int main() {
    pthread_t threads[5];
    
    // মিউটেক্স ইনিশিয়ালাইজ করা
    pthread_mutex_init(&mutex, NULL);

    // থ্রেড তৈরি করা
    for (int i = 0; i < 5; i++) {
        pthread_create(&threads[i], NULL, increment, NULL);
    }

    // থ্রেডের শেষে যাওয়া
    for (int i = 0; i < 5; i++) {
        pthread_join(threads[i], NULL);
    }

    // মিউটেক্স ডেস্ট্রয় করা
    pthread_mutex_destroy(&mutex);

    printf("All threads finished.\n");
    return 0;
}

এখানে, pthread_mutex_lock() এবং pthread_mutex_unlock() ফাংশনগুলো ব্যবহার করে মিউটেক্স সিঙ্ক্রোনাইজেশন পরিচালনা করা হয়েছে।


3. Mutex Handling

মিউটেক্স (mutual exclusion) একটি সিঙ্ক্রোনাইজেশন প্রক্রিয়া যা একাধিক থ্রেডের মধ্যে একে অপরের কাছে একসাথে ডেটা অ্যাক্সেসে বাধা দেয়। এটি একটি লকিং মেকানিজম, যা নিশ্চিত করে যে এক সময়ে শুধুমাত্র একটি থ্রেড মেমোরি বা রিসোর্স অ্যাক্সেস করতে পারে।

সিঙ্কট্যাক্স:

#include <pthread.h>

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
  • pthread_mutex_init(): মিউটেক্স ইনিশিয়ালাইজ করে।
  • pthread_mutex_lock(): মিউটেক্সে লক করে, যদি অন্য কোনো থ্রেড মিউটেক্সে লক করে থাকে, তাহলে এটি অপেক্ষা করবে।
  • pthread_mutex_unlock(): মিউটেক্স আনলক করে, অন্য থ্রেডের জন্য লক উপলব্ধ করে।
  • pthread_mutex_destroy(): মিউটেক্স ধ্বংস করে।

উদাহরণ: মিউটেক্সের মাধ্যমে দুটি থ্রেডের মধ্যে সিঙ্ক্রোনাইজেশন

#include <stdio.h>
#include <pthread.h>

pthread_mutex_t mutex;
int counter = 0;

void *increment(void *arg) {
    pthread_mutex_lock(&mutex);  // মিউটেক্স লক করা
    counter++;
    printf("Counter value: %d\n", counter);
    pthread_mutex_unlock(&mutex);  // মিউটেক্স আনলক করা
    return NULL;
}

int main() {
    pthread_t threads[5];
    
    pthread_mutex_init(&mutex, NULL);  // মিউটেক্স ইনিশিয়ালাইজ

    // থ্রেড তৈরি
    for (int i = 0; i < 5; i++) {
        pthread_create(&threads[i], NULL, increment, NULL);
    }

    // থ্রেডের শেষ হওয়া পর্যন্ত অপেক্ষা করা
    for (int i = 0; i < 5; i++) {
        pthread_join(threads[i], NULL);
    }

    pthread_mutex_destroy(&mutex);  // মিউটেক্স ধ্বংস

    return 0;
}

এখানে, counter ভেরিয়েবলটি একাধিক থ্রেড দ্বারা এক্সেস করা হচ্ছে, কিন্তু মিউটেক্স pthread_mutex_lock() এবং pthread_mutex_unlock() দ্বারা সিঙ্ক্রোনাইজ করা হয়েছে, যাতে একাধিক থ্রেড একসাথে এই ভেরিয়েবলটি পরিবর্তন করতে না পারে। এর ফলে ডেটার সঠিকতা বজায় থাকে।


সারসংক্ষেপ:

  • থ্রেড তৈরি: pthread_create() ব্যবহার করে থ্রেড তৈরি করা হয়।
  • সিঙ্ক্রোনাইজেশন: থ্রেডের মধ্যে সঠিক ডেটা ম্যানিপুলেশন নিশ্চিত করতে সিঙ্ক্রোনাইজেশন ব্যবহৃত হয়। এটি মিউটেক্স, সেমাফোর, বা কন্ডিশন ভেরিয়েবল দ্বারা করা হয়।
  • মিউটেক্স: একাধিক থ্রেডের মধ্যে ডেটা এক্সেস লক এবং আনলক করতে pthread_mutex_lock() এবং pthread_mutex_unlock() ব্যবহৃত হয়। pthread_mutex_init() দ্বারা মিউটেক্স ইনিশিয়ালাইজ করা হয় এবং pthread_mutex_destroy() দ্বারা মিউটেক্স ধ্বংস করা হয়।

থ্রেড ব্যবস্থাপনা এবং সিঙ্ক্রোনাইজেশন নিশ্চিত করতে এই কনসেপ্টগুলি অত্যন্ত গুরুত্বপূর্ণ, বিশেষত মাল্টিথ্রেডেড প্রোগ্রামে।

common.content_added_by

Deadlock এবং Race Condition এর প্রতিরোধ

211
211

Deadlock এবং Race Condition এর প্রতিরোধ

Deadlock এবং Race Condition দুটি গুরুত্বপূর্ণ সমস্যা যা মাল্টিথ্রেডেড প্রোগ্রামিংয়ে ঘটে। এই সমস্যাগুলি সাধারণত পারালাল এক্সিকিউশন এবং শেয়ার্ড রিসোর্স ব্যবহারের সময় ঘটে, এবং এটি সঠিকভাবে হ্যান্ডেল করা না হলে প্রোগ্রাম ক্র্যাশ হতে পারে বা অপ্রত্যাশিত আচরণ ঘটতে পারে। এদের প্রতিরোধের জন্য যথাযথ সিনক্রোনাইজেশন এবং লকারিং মেকানিজম ব্যবহার করা হয়।


১. Deadlock - ডেডলক

Deadlock একটি পরিস্থিতি যেখানে দুটি বা তার বেশি থ্রেড বা প্রসেস একে অপরকে সম্পূর্ণ করতে বাধা দেয় কারণ তারা একে অপরের রিসোর্সের জন্য অপেক্ষা করছে। এক্ষেত্রে, প্রতিটি থ্রেড বা প্রসেস অন্য থ্রেড বা প্রসেসের সম্পূর্ণ করার জন্য অপেক্ষা করে এবং এর ফলে প্রোগ্রামটি স্থির হয়ে যায়।

Deadlock এর ৪টি শর্ত:

  1. Mutual Exclusion: রিসোর্স এক সময়ে শুধুমাত্র একাধিক প্রসেস বা থ্রেডের দ্বারা ব্যবহৃত হতে পারে।
  2. Hold and Wait: একটি প্রসেসের কাছে কমপক্ষে একটি রিসোর্স আছে, এবং আরও রিসোর্সের জন্য অপেক্ষা করছে।
  3. No Preemption: রিসোর্সগুলি কোনও প্রসেস থেকে জোর করে নিয়ে নেওয়া সম্ভব নয়, অর্থাৎ, একবার একটি প্রসেস রিসোর্স পেলে সেটি ছেড়ে দেওয়া না হওয়া পর্যন্ত অন্য প্রসেস রিসোর্সটি ব্যবহার করতে পারবে না।
  4. Circular Wait: একটি প্রসেস একটি রিসোর্সের জন্য অপেক্ষা করছে, এবং সেই রিসোর্সের মালিক অন্য একটি রিসোর্সের জন্য অপেক্ষা করছে, এবং চক্র তৈরি হয়।

Deadlock প্রতিরোধ:

  1. Lock Ordering: রিসোর্সগুলির জন্য একটি নির্দিষ্ট আদেশ তৈরি করুন, এবং প্রতিটি থ্রেড সেই আদেশ অনুসারে রিসোর্স বরাদ্দ করবে। এটি Circular Wait এড়াতে সাহায্য করে।
    • উদাহরণ: রিসোর্স 1 বরাদ্দ করার আগে রিসোর্স 2 বরাদ্দ করা যাবে না।
  2. Deadlock Detection and Recovery: Deadlock সনাক্ত করতে একটি ডেডলক ডিটেকশন অ্যালগরিদম ব্যবহার করুন এবং প্রয়োজনে প্রসেস বা থ্রেড পুনরায় আরম্ভ করতে বা বাতিল করতে পারেন।
  3. Prevention of Circular Wait: একাধিক থ্রেডের মধ্যে রিসোর্সের জন্য অপেক্ষার চক্র এড়ানোর জন্য প্রয়োজনীয় ব্যবস্থা নিন। যেমন, থ্রেডগুলির মধ্যে রিসোর্স বরাদ্দের আগে একটি নির্দিষ্ট ক্রম অনুসরণ করা।
  4. Resource Allocation Graph (RAG): রিসোর্স এবং প্রসেসের জন্য গ্রাফ ব্যবহার করা, যেখানে প্রতিটি রিসোর্স ও প্রসেসের জন্য একটি নোড থাকে এবং তাদের সম্পর্ক চিহ্নিত করা হয়। Deadlock সনাক্ত করা হলে, সিস্টেমটি পুনরায় চালু করা যায়।

২. Race Condition - রেস কন্ডিশন

Race Condition একটি সমস্যা যা ঘটে যখন একাধিক থ্রেড বা প্রসেস একটি শেয়ার্ড রিসোর্সে একসাথে প্রবেশ করে এবং এই অ্যাক্সেসকে সঠিকভাবে নিয়ন্ত্রিত না করা হলে এটি অপ্রত্যাশিত ফলাফল তৈরি করে। এটি সাধারণত তখন ঘটে যখন কোনো প্রসেস বা থ্রেড একটি রিসোর্সে কাজ করছে এবং অন্য একটি থ্রেড বা প্রসেস সেই রিসোর্সে পরিবর্তন আনতে পারে।

Race Condition এর প্রতিরোধ:

  1. Mutex (Mutual Exclusion) Locks: রেস কন্ডিশন প্রতিরোধের জন্য সবচেয়ে সাধারণ উপায় হল mutex বা mutual exclusion লকার ব্যবহার করা। এটি নিশ্চিত করে যে একাধিক থ্রেড একে অপরের সাথে শেয়ার করা রিসোর্সে একযোগভাবে প্রবেশ করতে না পারে।
    • উদাহরণ:

      pthread_mutex_t lock;
      pthread_mutex_init(&lock, NULL);
      pthread_mutex_lock(&lock);  // রিসোর্স অ্যাক্সেসের আগে লক করুন
      // রিসোর্সে কাজ করুন
      pthread_mutex_unlock(&lock);  // কাজ শেষ হলে লক খুলে দিন
  2. Critical Section: একটি অংশ বা ব্লক যেখানে একে অপরের সাথে সম্পর্কিত কোড একসাথে একাধিক থ্রেড বা প্রসেস দ্বারা সম্পন্ন হতে পারে না। এই সেকশনে কেবল একটি থ্রেড বা প্রসেসই কাজ করতে পারে।
    • উদাহরণ:

      // উদাহরণ: Critical Section
      void function() {
          // Mutex লকারের মাধ্যমে একে একে একাধিক থ্রেডের অ্যাক্সেস নিয়ন্ত্রণ করা হচ্ছে
          pthread_mutex_lock(&lock);
          // শেয়ারড রিসোর্সে কাজ
          pthread_mutex_unlock(&lock);
      }
  3. Semaphores: সেমাফোর একটি সিনক্রোনাইজেশন টুল যা থ্রেড বা প্রসেসের মধ্যে সিগন্যাল আদান প্রদান করতে ব্যবহৃত হয়। সেমাফোর ব্যবহার করে একটি রিসোর্সে অ্যাক্সেস নিয়ন্ত্রণ করা যায়। এটি কাউন্টিং বা বাইনারি সেমাফোর হিসাবে কাজ করতে পারে।
    • উদাহরণ:

      sem_t sem;
      sem_init(&sem, 0, 1);  // সেমাফোরের প্রাথমিক মান 1
      
      // একাধিক থ্রেড সেমাফোরের মাধ্যমে একে অপরের সাথে যোগাযোগ করবে
      sem_wait(&sem);  // রিসোর্সে প্রবেশের জন্য সেমাফোর পেতে হবে
      // রিসোর্সে কাজ করুন
      sem_post(&sem);  // কাজ শেষ হলে সেমাফোর মুক্ত করুন
  4. Atomic Operations: Atomic operations রেস কন্ডিশন প্রতিরোধে একটি শক্তিশালী উপায়। এটি নিশ্চিত করে যে একটি রিসোর্সে কাজ করার সময় কোনও অন্য থ্রেড বা প্রসেস এটি পরিবর্তন করতে পারে না, কারণ এটি একমাত্র একটি অ্যাটমিক (অবিচ্ছিন্ন) অপারেশন হবে।
  5. Read/Write Locks: Read/Write locks ব্যবহার করে আপনি সেট করতে পারেন যে একাধিক রিডার একই সময়ে শেয়ার্ড রিসোর্স পড়তে পারে, তবে রাইটার একমাত্র একাই কাজ করতে পারে। এই ধরনের সিঙ্ক্রোনাইজেশন রেস কন্ডিশন প্রতিরোধে সহায়ক।

সারসংক্ষেপ

সমস্যাবর্ণনাপ্রতিরোধের উপায়
Deadlockএকাধিক থ্রেড বা প্রসেস একে অপরকে সম্পূর্ণ করতে বাধা দেয়।Lock Ordering, Deadlock Detection, Resource Allocation Graph
Race Conditionএকাধিক থ্রেড বা প্রসেস শেয়ার করা রিসোর্সে একসাথে প্রবেশ করে।Mutex Locking, Critical Section, Semaphores, Atomic Operations
  • Deadlock এড়াতে resource allocation এবং lock ordering পদ্ধতি ব্যবহার করা হয়, যেখানে থ্রেডগুলি নির্দিষ্ট অর্ডারে রিসোর্স অ্যাক্সেস করতে পারে।
  • Race Condition এড়াতে mutexes, semaphores, এবং atomic operations ব্যবহার করা হয়, যা একসাথে রিসোর্স অ্যাক্সেস নিয়ন্ত্রণ করে।
common.content_added_by

C তে Concurrent Programming Techniques

258
258

C তে Concurrent Programming Techniques

কনকারেন্ট প্রোগ্রামিং (Concurrent Programming) হলো একাধিক কাজ বা প্রোগ্রাম অংশকে সমান্তরালভাবে (simultaneously) বা পাশাপাশি চালানোর কৌশল। এটি মাল্টি-থ্রেডিং, মাল্টি-প্রসেসিং এবং প্যারালাল প্রোগ্রামিংয়ের অন্তর্গত, যেখানে একাধিক কার্যক্রম একে অপরের সাথে সমান্তরালে (বা কিছু ক্ষেত্রে, একে অপরের সাথে মিশ্রিতভাবে) চলে। C প্রোগ্রামিং ভাষায় কনকারেন্ট প্রোগ্রামিংয়ের জন্য বেশ কিছু পদ্ধতি এবং লাইব্রেরি রয়েছে।

এখানে C তে কনকারেন্ট প্রোগ্রামিং প্রযুক্তি এবং তাদের ব্যবহার নিয়ে আলোচনা করা হবে।


১. Multithreading (মাল্টি-থ্রেডিং)

মাল্টি-থ্রেডিং হলো একটাই প্রোগ্রাম বা প্রসেসের মধ্যে একাধিক থ্রেড তৈরি করা, যেখানে প্রতিটি থ্রেড একটি পৃথক কার্য সম্পাদন করে। C তে মাল্টি-থ্রেডিং সাধারণত pthread লাইব্রেরি ব্যবহার করে পরিচালিত হয়। থ্রেডগুলি একে অপরের সাথে সমান্তরালভাবে কাজ করতে পারে, যা প্রোগ্রামের কর্মক্ষমতা এবং পারফরম্যান্স বাড়ায়।

pthread লাইব্রেরি:

pthread (POSIX threads) হলো C এর জন্য একটি স্ট্যান্ডার্ড থ্রেড লাইব্রেরি, যা মাল্টি-থ্রেডিং পরিচালনার জন্য ব্যবহৃত হয়।

  • pthread_create(): নতুন থ্রেড তৈরি করা।
  • pthread_join(): থ্রেডের কার্যক্রম সম্পূর্ণ হওয়া পর্যন্ত অপেক্ষা করা।
  • pthread_exit(): থ্রেডের কার্যক্রম শেষ হওয়া।

উদাহরণ: মাল্টি-থ্রেডিং ব্যবহার করে দুইটি থ্রেড চালানো

#include <stdio.h>
#include <pthread.h>

// থ্রেডের কাজ
void* print_message(void* ptr) {
    printf("Hello from thread!\n");
    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    // প্রথম থ্রেড তৈরি
    pthread_create(&thread1, NULL, print_message, NULL);
    // দ্বিতীয় থ্রেড তৈরি
    pthread_create(&thread2, NULL, print_message, NULL);

    // থ্রেডের কাজ শেষ হওয়া পর্যন্ত অপেক্ষা করা
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    printf("Hello from main thread!\n");
    return 0;
}

এখানে দুটি থ্রেড তৈরি করা হয়েছে, এবং প্রতিটি থ্রেড "Hello from thread!" মেসেজ প্রিন্ট করবে।


২. Shared Memory (শেয়ারড মেমরি)

শেয়ারড মেমরি হলো একাধিক প্রসেসের মধ্যে একে অপরের ডেটা শেয়ার করার পদ্ধতি। C তে শেয়ারড মেমরি ব্যবহারের জন্য shmget(), shmat(), shmdt(), এবং shmctl() ফাংশনগুলি ব্যবহার করা হয়।

  • shmget(): শেয়ারড মেমরি তৈরি বা পাওয়ার জন্য ব্যবহৃত হয়।
  • shmat(): শেয়ারড মেমরিতে অ্যাক্সেস করার জন্য ব্যবহৃত হয়।
  • shmdt(): শেয়ারড মেমরি আনম্যাপ করার জন্য ব্যবহৃত হয়।

উদাহরণ: শেয়ারড মেমরি ব্যবহারের মাধ্যমে দুটি প্রসেসের মধ্যে ডেটা শেয়ার করা

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main() {
    key_t key = ftok("shmfile", 65);
    int shmid = shmget(key, 1024, 0666|IPC_CREAT);

    char *str = (char*) shmat(shmid, NULL, 0);

    printf("Write data to shared memory: ");
    gets(str);  // ইউজার ইনপুট নেয়া

    printf("Data written to shared memory: %s\n", str);

    shmdt(str);  // শেয়ারড মেমরি ডিসঅ্যাসোসিয়েট করা

    return 0;
}

এই উদাহরণে, একটি প্রসেস শেয়ারড মেমরিতে ডেটা লেখে এবং অন্য প্রসেস সেই ডেটা পড়ে।


৩. Message Queues (মেসেজ কিউ)

মেসেজ কিউ ব্যবহৃত হয় একাধিক প্রসেসের মধ্যে ডেটা আদান-প্রদান করার জন্য। C তে মেসেজ কিউ পরিচালনা করতে msgget(), msgsnd(), msgrcv(), এবং msgctl() ফাংশনগুলি ব্যবহৃত হয়।

  • msgget(): একটি নতুন মেসেজ কিউ তৈরি বা খোঁজার জন্য ব্যবহৃত হয়।
  • msgsnd(): কিউতে একটি মেসেজ পাঠানোর জন্য ব্যবহৃত হয়।
  • msgrcv(): কিউ থেকে একটি মেসেজ গ্রহণ করার জন্য ব্যবহৃত হয়।

উদাহরণ: মেসেজ কিউ ব্যবহার করে দুটি প্রসেসের মধ্যে মেসেজ পাঠানো এবং গ্রহণ করা

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct msg_buffer {
    long msg_type;
    char msg_text[100];
};

int main() {
    key_t key = ftok("progfile", 65);
    int msgid = msgget(key, 0666 | IPC_CREAT);

    struct msg_buffer message;

    // মেসেজ পাঠানো
    message.msg_type = 1;
    printf("Write message: ");
    fgets(message.msg_text, sizeof(message.msg_text), stdin);

    msgsnd(msgid, &message, sizeof(message), 0);
    printf("Message sent: %s", message.msg_text);

    // মেসেজ গ্রহণ করা
    msgrcv(msgid, &message, sizeof(message), 1, 0);
    printf("Message received: %s", message.msg_text);

    msgctl(msgid, IPC_RMID, NULL);  // মেসেজ কিউ নিষ্ক্রিয় করা
    return 0;
}

এখানে, একটি প্রসেস মেসেজ পাঠাচ্ছে এবং অন্য প্রসেস মেসেজ গ্রহণ করছে।


৪. Semaphores (সেমাফোর)

সেমাফোর হলো একটি কনকারেন্ট প্রোগ্রামিং প্রযুক্তি যা একাধিক থ্রেড বা প্রসেসের মধ্যে সিঙ্ক্রোনাইজেশন নিশ্চিত করতে ব্যবহৃত হয়। এটি বিশেষ করে ক্রিটিকাল সেকশন বা একাধিক থ্রেডের মধ্যে ডেটা রেস কন্ডিশন এড়াতে সহায়ক।

C তে সেমাফোর ব্যবহারের জন্য sem_init(), sem_wait(), sem_post(), এবং sem_destroy() ফাংশনগুলি ব্যবহৃত হয়।

  • sem_wait(): সেমাফোরের মান কমায় (যদি মান ইতিবাচক হয়) এবং থ্রেড বা প্রসেসকে ব্লক করে।
  • sem_post(): সেমাফোরের মান বাড়ায় এবং ব্লক করা থ্রেড বা প্রসেসকে মুক্ত করে।

সারসংক্ষেপ

  1. মাল্টি-থ্রেডিং (Multithreading): একই প্রোগ্রামে একাধিক থ্রেড ব্যবহার করে কার্যক্রম দ্রুত সম্পাদন।
  2. শেয়ারড মেমরি (Shared Memory): একাধিক প্রসেসের মধ্যে তথ্য শেয়ার করা।
  3. মেসেজ কিউ (Message Queues): প্রসেসের মধ্যে মেসেজ পাঠানো এবং গ্রহণ করা।
  4. সেমাফোর (Semaphores): থ্রেড বা প্রসেসের মধ্যে সিঙ্ক্রোনাইজেশন নিশ্চিত করা।

সি প্রোগ্রামিংয়ে কনকারেন্ট প্রোগ্রামিংয়ের কৌশলগুলি ব্যবহার করে বিভিন্ন কার্যক্রম একযোগে সম্পাদন করা যায়, যা প্রোগ্রামের পারফরম্যান্স এবং কার্যকারিতা উন্নত করতে সহায়ক।

common.content_added_by
টপ রেটেড অ্যাপ

স্যাট অ্যাকাডেমী অ্যাপ

আমাদের অল-ইন-ওয়ান মোবাইল অ্যাপের মাধ্যমে সীমাহীন শেখার সুযোগ উপভোগ করুন।

ভিডিও
লাইভ ক্লাস
এক্সাম
ডাউনলোড করুন
Promotion